package com.cskaoyan.javase.oop2._1extends._7initialization._2basic;

import java.nio.channels.Pipe;

/**
 * 我们通过一个引例，练习来讲解这个问题：
 * 创建一个Person类，有name属性和eat方法
 * 创建一个Star类，有stageName属性和sing方法
 * Star类要继承Person类
 * 创建Star类对象，画出这个过程的内存图，描述子类对象初始化的过程。
 *
 * 子类对象的初始化问题,研究以下问题:
 * 1.new创建子类对象，肯定触发子类类加载，那么父类呢？父类会不会类加载呢?
 *      会类加载,而且类加载的顺序是"先父后子"的
 *      所以一旦new创建子类对象(实际上一旦触发子类类加载),都会优先类加载父类
 *      (从方法栈帧进栈来说,父类的clinit方法栈帧先进栈,子类后进栈)
 *      所以这也是一种触发类加载的时机,于是类加载的时机:
 *          a.new对象
 *          b.启动main方法
 *          c.访问静态成员
 *          d.触发子类类加载,会优先类加载父类
 *      当然如果处在继承层次中,那么类加载会从顶层父类开始.
 *
 * 2.new创建子类对象，会一起创建父类对象吗？
 * 不会,new谁的对象,就是创建谁的对象,不会创建其它任何对象,只会创建一个对象
 *
 *
 * 3.既然只会创建一个子类对象,那么父类的成员变量如何存储呢?
 * 肯定是存在子类对象当中的,但是父类成员变量毕竟是继承自父类的,不是子类自身
 * 所以子类对象中会专门开辟一片独立的区域，用来存储父类的成员变量
 * 而子类自身的成员仍会存储在自身对象当中
 * 这样子类对象就被划分为了两个区域:
 *      a.用来存储父类成员变量的区域,这片区域非常类似于一个父类对象,可以近似的看成一个父类对象(它不是对象,只是子类对象中的一片内存区域)
 *      而且实际使用中,这片区域也确实可以当成一个父类对象使用
 *      这片近似看成父类对象的区域,使用super关键字指向
 *      当然这是一个子类对象,super关键字必须在子类的成员方法,构造器,构造代码块中使用
 *      和this关键字的使用场景一样,指向父类成员的区域,近似看成指向父类对象
 *
 *      b.用来存储子类自身成员变量的区域
 *
 * 4.既然子类对象中要存储父类成员变量,那么父类的成员变量和子类的成员变量,它们的赋值如何进行呢?
 * 首先要明确,默认初始化,永远最先进行,无论是父类成员,还是子类自身成员变量,它们的赋值都是在默认值的基础上完成的.所以我们不研究默认值如何赋值.
 * 重点研究除了默认值以外的其他赋值方式.
 *
 * 首先第一个问题:
 * 父子类成员变量的赋值,赋值顺序应该是什么样的?
 * 按理说是"先父后子",我们通过代码验证也确实是这样的,它们的赋值确实是"先父后子"的
 *
 *
 * 第二个问题:
 * 子类对象当中,成员变量赋值的"先父后子"是如何保证的呢?
 * 假设:
 * 在给某个类的对象成员变量赋值过程中,该类的构造器是最后执行的
 * 所以只要保证父类的构造器先于子类构造器执行,那么就能够保证成员变量赋值的"先父后子"
 * 这样就能保证 父类中所有的赋值手段都执行完毕,才能够执行子类中的赋值手段,这样就能够保证"先父后子"
 *
 * 通过构造代码块验证,我们发现父类构造器确实先于子类构造器执行.
 *
 * 父类构造器确实先于子类构造器执行保证了成员变量赋值的"先父后子"
 *
 * 5.代码中,子类中,没有任何位置去调用父类构造器,那么为什么父类构造器先执行呢?
 *
 * 子类对象的隐式初始化
 * 在一个Java类中的某一个构造器中,只要该构造器的第一行没有this或者super去显式的调用其他构造器,那么它就隐含语句:
 * super();
 * 表示调用父类的无参构造器
 * 这时就能够保证父子类构造器的"先父后子"执行
 * 也就可以保证父子类成员变量的"先父后子"赋值
 *
 * 子类对象的隐式初始化会调用父类的无参构造器,所以不能给父类成员变量赋值
 * 如果想要给父类成员变量赋值,那么就必须调用父类的有参构造器
 *
 * 这种直接的调用父类某个构造器的子类对象初始化方式,称之为子类对象的显式初始化
 *
 * 子类对象的显式初始化
 * 在子类构造器的第一行,直接使用:
 * super(实参列表);
 * 表示调用父类的对应参数的构造器,来完成父类成员变量的赋值
 *
 *
 * @since 09:24
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        Star s = new Star();
        System.out.println(s.stageName);

        Star s2 = new Star("吴亦凡");
        System.out.println(s2.name);
        System.out.println(s2.stageName);
    }
}

class Person {
    /*static {
        System.out.println("Person类类加载了!");
    }*/
    /*{
        System.out.println("父类的构造代码块执行了!");
    }*/

    String name = "张三";

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    public void eat() {
        System.out.println("人都要吃饭!");
    }
}

class Star extends Person {
    /*static {
        System.out.println("Star类类加载了!");
    }*/

    /*{
        System.out.println("子类的构造代码块执行了!");
    }*/
    String stageName = name + "的姐姐";

    public Star() {
        // 隐含super(); 去调用父类无参构造器
    }

    public Star(String name) {
        super(name);
    }

    public void sing() {
        System.out.println("唱一首爱的供养!");
    }
}